// src/models/file.model.js
/**
 * 文件模型
 * @description 定义文件上传相关的数据库模型
 */

import { DataTypes } from "sequelize";
import { BadRequestError } from "../utils/errors.js";

export default (sequelize) => {
  const File = sequelize.define(
    "File",
    {
      id: {
        type: DataTypes.UUID,
        primaryKey: true,
        defaultValue: DataTypes.UUIDV4,
        comment: "文件唯一ID",
      },
      file_hash: {
        type: DataTypes.STRING(32),
        allowNull: true,
        comment: "文件哈希值",
      },
      file_name: {
        type: DataTypes.STRING(255),
        allowNull: false,
        comment: "原始文件名",
      },
      file_path: {
        type: DataTypes.STRING(512),
        allowNull: true,
        comment: "文件存储路径",
      },
      file_url: {
        type: DataTypes.STRING(512),
        allowNull: true,
        comment: "文件访问URL",
      },
      file_size: {
        type: DataTypes.BIGINT,
        allowNull: false,
        comment: "文件大小(字节)",
        validate: {
          min: 0,
        },
      },
      file_type: {
        type: DataTypes.STRING(100),
        allowNull: false,
        comment: "文件MIME类型",
      },
      file_extension: {
        type: DataTypes.STRING(20),
        allowNull: true,
        comment: "文件扩展名",
      },
      user_id: {
        type: DataTypes.UUID,
        allowNull: false,
        comment: "上传用户ID",
      },
      upload_type: {
        type: DataTypes.ENUM(
          "product",
          "thumbnail",
          "gallery",
          "sku",
          "avatar",
          "default"
        ),
        defaultValue: "default",
        comment: "上传类型",
      },
      status: {
        type: DataTypes.ENUM(
          "pending",
          "uploading",
          "completed",
          "failed",
          "deleted"
        ),
        defaultValue: "pending",
        comment: "上传状态",
      },
      chunk_info: {
        type: DataTypes.JSON,
        allowNull: true,
        comment: "分片上传信息",
      },
      error_message: {
        type: DataTypes.TEXT,
        allowNull: true,
        comment: "错误信息",
      },
      completed_at: {
        type: DataTypes.DATE,
        allowNull: true,
        comment: "完成时间",
      },
    },
    {
      tableName: "files",
      timestamps: true,
      paranoid: true,
      indexes: [
        { fields: ["file_hash"] },
        { fields: ["user_id"] },
        { fields: ["upload_type"] },
        { fields: ["status"] },
        { fields: ["created_at"] },
      ],
      hooks: {
        beforeValidate: (file) => {
          // 自动提取文件扩展名
          if (file.file_name && !file.file_extension) {
            const lastDot = file.file_name.lastIndexOf(".");
            if (lastDot > 0) {
              file.file_extension = file.file_name
                .slice(lastDot + 1)
                .toLowerCase();
            }
          }
        },
      },
    }
  );

  // 关联用户模型（假设你的用户模型名为User）
  File.associate = (models) => {
    // File.belongsTo(models.User, {
    //   foreignKey: "user_id",
    //   as: "uploader",
    //   onDelete: "CASCADE"
    // });

    File.hasMany(models.FileChunk, {
      foreignKey: "file_id",
      as: "chunks",
    });

  };

  // 实例方法：获取公开文件信息
  File.prototype.getPublicInfo = function () {
    return {
      id: this.id,
      url: this.file_url,
      name: this.file_name,
      size: this.file_size,
      type: this.file_type,
      uploadType: this.upload_type,
      createdAt: this.created_at,
    };
  };

  /**
   * 通过文件哈希查找文件
   */
  File.findByHash = async function (fileHash) {
    return await this.findOne({
      where: { file_hash: fileHash },
      paranoid: false, // 包括已软删除的记录
    });
  };

  /**
   * 检查文件是否存在（基于文件哈希）
   */
  File.checkExistsByHash = async function (fileHash) {
    const file = await this.findByHash(fileHash);
    if (file && ["completed", "active"].includes(file.status)) {
      return file.getPublicInfo();
    }
    return null;
  };
  /**
   * 检查文件是否存在（基于文件名）
   */
  File.checkExistsByName = async function (fileName) {
    const file = await this.findOne({
      where: { file_name: fileName },
      paranoid: false,
    });
    if (file && ["completed", "active"].includes(file.status)) {
      return file.getPublicInfo();
    }
    return null;
  };

  return File;
};
